package com.mybatis.sqlsession;

import com.mybatis.entity.Configuration;
import com.mybatis.entity.MappedStatement;
import com.mybatis.exception.MapperLabelException;
import com.mybatis.exception.SelectOntException;

import java.lang.reflect.*;
import java.util.List;

/**
 * 创建人: yyn
 * 创建时间:2021/7/9 7:52
 */
public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <T> List<T> selectList(String statementId, Object... param) throws Exception {
        // TODO 执行器查询
        Executor executor = new SimpleExecutor(configuration);
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        return executor.query(mappedStatement, param);
    }

    @Override
    public <T> T selectOne(String statementId, Object... param) throws Exception {
        List<Object> objectList = selectList(statementId, param);
        if (objectList == null || objectList.size() != 1) {
            throw new SelectOntException("数据为空或有多个");
        }
        return (T) objectList.get(0);
    }

    @Override
    public int insert(String statementId, Object... param) throws Exception {
        return update(statementId, param);
    }

    @Override
    public int update(String statementId, Object... param) throws Exception {
        Executor executor = new SimpleExecutor(configuration);
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        return executor.doUpdate(mappedStatement, param);
    }

    @Override
    public int delete(String statementId, Object... param) throws Exception {
        return update(statementId, param);
    }

    @Override
    public <T> T getMapper(Class<?> type) {
        Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{type},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 底层都还是去执行JDBC代码 //根据不同情况，来调用selctList或者selectOne
                        // 准备参数 1：statmentid :sql语句的唯一标识：namespace.id= 接口全限定名.方法名
                        // 方法名：findAll
                        String methodName = method.getName();
                        String className = method.getDeclaringClass().getName();

                        String statementId = className + "." + methodName;
                        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
                        switch (mappedStatement.getType()) {
                            case "select":
                                Type genericReturnType = method.getGenericReturnType();
                                // 判断是否进行了 泛型类型参数化
                                if (genericReturnType instanceof ParameterizedType) {
                                    List<Object> objects = selectList(statementId, args);
                                    return objects;
                                }
                                return selectOne(statementId, args);
                            case "insert":
                                return insert(statementId, args);
                            case "update":
                                return update(statementId, args);
                            case "delete":
                                return delete(statementId, args);
                            default:
                                throw new MapperLabelException("标签错误");
                        }
                    }
                });
        return (T) proxyInstance;

    }
}
